package jmetal.metaheuristics.singleObjective.panmitic;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.RecursiveTask;

import jmetal.core.Operator;
import jmetal.core.Solution;
import jmetal.core.SolutionSet;
import jmetal.util.JMException;

public class PanmiticFTGAParallelUnit extends RecursiveTask<SolutionSet> {
	private Operator mutationOperator;
	private Operator selectionOperator;
	private Operator crossoverOperator;
	private SolutionSet parentsPopulation;
	private int populationSize;
	protected PanmiticFTGA master;

	public PanmiticFTGAParallelUnit(Operator mutationOperator, Operator crossoverOperator, Operator selectionOperator,
			SolutionSet parentsPopulation, PanmiticFTGA master, int populationSize) {
		super();
		this.mutationOperator = mutationOperator;
		this.selectionOperator = selectionOperator;
		this.crossoverOperator = crossoverOperator;
		this.populationSize = populationSize;
		this.parentsPopulation = parentsPopulation;
		this.master = master;
	}

	protected SolutionSet compute() {
		SolutionSet result = new SolutionSet(populationSize);

		if (populationSize == 0) {
			return null;
		}

		if (populationSize == 2) {
			generateOffsprings(result);
			return result;
		}

		List<RecursiveTask<SolutionSet>> forks = new ArrayList<>();

		for (int i = 0; i < (this.populationSize-2)/2; i++) {
			PanmiticFTGAParallelUnit unit = new PanmiticFTGAParallelUnit(mutationOperator, crossoverOperator,
					selectionOperator, parentsPopulation, master, 2);
			unit.fork();
			forks.add(unit);
		}

		// Somando o resultado das tarefas
		for (RecursiveTask<SolutionSet> subTask : forks) {
			// Pega o retorno de cada task, quando usamos join, e soma na
			// variavel RESULT
			SolutionSet setFilho = subTask.join();
			for (int i = 0; i < setFilho.size(); i++) {
				result.add(setFilho.get(i));
			}
		}

		return result;
	}

	private void generateOffsprings(SolutionSet result) {
		try {
			Solution[] parents = new Solution[2];

			parents[0] = (Solution) selectionOperator.execute(parentsPopulation);
			parents[1] = (Solution) selectionOperator.execute(parentsPopulation);

			Solution[] offspring = (Solution[]) crossoverOperator.execute(parents);

			mutationOperator.execute(offspring[0]);
			mutationOperator.execute(offspring[1]);

			master.getProblem().evaluate(offspring[0]);
			master.getProblem().evaluate(offspring[1]);

			result.add(offspring[0]);
			result.add(offspring[1]);
		} catch (JMException e) {
			e.printStackTrace();
		}
	}
}
